Skip to content

fix: stop resolve() from leaking foreign envs (e.g. hatch) into the venv collection#1507

Open
StellaHuang95 wants to merge 1 commit into
microsoft:mainfrom
StellaHuang95:hatch
Open

fix: stop resolve() from leaking foreign envs (e.g. hatch) into the venv collection#1507
StellaHuang95 wants to merge 1 commit into
microsoft:mainfrom
StellaHuang95:hatch

Conversation

@StellaHuang95
Copy link
Copy Markdown
Contributor

@StellaHuang95 StellaHuang95 commented May 5, 2026

Context

@flying-sheep reported three related bugs — #1471, #1485, #1491. The two venv-related ones both traced to the same root cause in VenvManager.resolve().

Hatch envs structurally look like venvs (they have a pyvenv.cfg), so until very recently PET classified them as Venv and they passed through resolveVenvPythonEnvironmentPath. Every successful resolve() call also mutated this.collection via addEnvironment(resolved, true). So whenever anything called resolve() for a hatch path — Python: Select Interpreter, Pylance startup, a test runner asking for execInfo, another extension querying the env — the hatch env got persisted under venv.

The original side effect dates back to commit 9363bc1 (Oct 2024), when the extension only had system and venv managers and the author assumed any successful resolve() was a newly discovered venv worth caching. That assumption stopped being true once the API supported third-party managers.

Upstream fix has now landed in PET

As of microsoft/python-environment-tools#460 (commit d581272), PET now has a dedicated pet-hatch locator:

  • New LocatorKind::Hatch and PythonEnvironmentKind::Hatch.
  • Registered before the Venv locator, so it claims hatch envs first.
  • Matches hatch's real storage layout (<data_dir>/env/virtual/<project_name>/<project_id>/<venv_name>), honors HATCH_DATA_DIR, and reads [tool.hatch.dirs.env].virtual from pyproject.toml / hatch.toml.

That fixes the structural source of the hatch-as-venv misclassification.

What this PR does

This PR is a complementary, defense-in-depth correction in src/managers/builtin/venvManager.ts:

 if (resolved) {
     if (resolved.envId.managerId === `${PYTHON_EXTENSION_ID}:venv`) {
-        // This is just like finding a new environment or creating a new one.
-        // Add it to collection, and trigger the added event.
-        this.addEnvironment(resolved, true);
-
         // We should only return the resolved env if it is a venv.
         return resolved;
     }
 }
 return undefined;

resolve() is now a pure query: "given a path, are you the manager for it?" It still returns the resolved env (every consumer of resolve() keeps working), it just stops mutating state. Cached venvs continue to land in this.collection through the normal discovery and creation paths, which is the only path that should be writing to it.

Why keep this PR alongside the PET fix

Even with PET correctly classifying hatch envs, VenvManager.resolve() mutating this.collection is an invariant violation worth correcting:

  • General cross-manager overlap. Anything that produces a pyvenv.cfg-shaped env (tox, nox, custom bootstrap scripts, future tools) would re-introduce the same class of leak. With resolve() as a pure query, no future overlap can silently grow the venv collection.
  • Locator-ordering regressions. If PET's locator priority ever shifts again, this change keeps the venv manager from quietly absorbing whatever lands in its lap.

@eleanorjboyd
Copy link
Copy Markdown
Member

From what I can tell the PR is a valid defensive fix, but the root cause is that PET has no concept of Hatch environments. Since hatch envs have pyvenv.cfg, the Venv locator here claims them. We would need to add Hatch as supported in PET.

This fix is still useful as defense-in-depth (resolve shouldn't mutate state), let me look at this more to see if we still want this PR then, in addition to any PET changes.

@flying-sheep
Copy link
Copy Markdown
Contributor

flying-sheep commented May 6, 2026

the root cause is that PET has no concept of Hatch environments. […] We would need to add Hatch as supported in PET.

Hatch environments are usually regular venvs that exist in specific locations, but not always. Hatch can use any kind of environment via plugin, e.g. you could make Hatch create conda envs instead, or docker images.

So I’d phrase that more generally: PET has no concept of env managers that manage a specific subset of envs of a known type – in other words, project-aware env managers like Hatch should be able to claim certain envs with a higher specificity than more generic / base env managers (which aren’t project-aware).

PS: don’t you have the same issue with Poetry already? It also just creates regular venvs, right?

@eleanorjboyd
Copy link
Copy Markdown
Member

@flying-sheep the following is merged in the PET extension which should help make sure Hatch environments do not get picked up: https://github.com/microsoft/python-environment-tools/commit/d58127285a6571fe4e0589a5c4f9220e559207…. @StellaHuang95 could you go through this PR once more now and just update it and the description given what we discussed about PET needing to recognize the env type but then about this change being a good additional stop-gate.

@StellaHuang95
Copy link
Copy Markdown
Contributor Author

@flying-sheep the following is merged in the PET extension which should help make sure Hatch environments do not get picked up: https://github.com/microsoft/python-environment-tools/commit/d58127285a6571fe4e0589a5c4f9220e559207…. @StellaHuang95 could you go through this PR once more now and just update it and the description given what we discussed about PET needing to recognize the env type but then about this change being a good additional stop-gate.

@eleanorjboyd Sure, now that fix on the PET side is in, hatch envs get classified correctly at the source, so I've reframed the description of the PR to be more generic, basically resolve() just stops mutating this.collection. Same one-line change, but it's there to catch anything else that ends up looking like a venv (tox, nox, hatch plugin envs, random custom scripts) rather than being the fix for hatch specifically.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants